package spring.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.support.GeneratedKeyHolder;
import org.springframework.jdbc.support.KeyHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import spring.bean.User;
import spring.mapper.UserMapper;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

@Service
public class UserService {

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    UserMapper userMapper;

    public User getUserById(long id) {
        return jdbcTemplate.execute((Connection conn) -> {
            try (var ps = conn.prepareStatement("SELECT * FROM users WHERE id = ?")) {
                ps.setObject(1, id);
                try (var rs = ps.executeQuery()) {
                    if (rs.next()) {
                        return new User(
                                rs.getLong("id"),
                                rs.getString("name"),
                                rs.getString("password"),
                                rs.getString("email"));
                    }
                    throw new RuntimeException("User not found by id: " + id);
                }
            }
        });
    }

    public User getUserByIdWithMapper(long id) {
        return userMapper.getUserById(id);
    }

    public List<User> getUserByName(String name) {
        return jdbcTemplate.execute("SELECT * FROM users WHERE name = ?", (PreparedStatement ps) -> {
           ps.setObject(1, name);
            try (var rs = ps.executeQuery()) {
                List<User> users = new ArrayList<>();
                while (rs.next()) {
                    users.add(new User(
                            rs.getLong("id"),
                            rs.getString("name"),
                            rs.getString("password"),
                            rs.getString("email")));
                }
                return users;
            }
        });
    }

    public List<User> getUserByNameWithMapper(String name) {
        return userMapper.getUserByName(name);
    }

    public User getUserByEmail(String email) {
        return jdbcTemplate.queryForObject("SELECT * FROM users WHERE email = ?", (ResultSet rs, int row) -> new User(
                        rs.getLong("id"),
                        rs.getString("name"),
                        rs.getString("password"),
                        rs.getString("email")),
                email);
    }

    public int updateUser(User user) {
        int rc = jdbcTemplate.update("UPDATE users SET name = ? WHERE id = ?", user.getName(), user.getId());
        if (rc != 1) {
            throw new RuntimeException("User not found by id: " + user.getId());
        }
        return rc;
    }

    @Transactional
    public User register(String name, String password, String email) {
        KeyHolder holder = new GeneratedKeyHolder();
        if (1 != jdbcTemplate.update((conn) -> {
            PreparedStatement ps = conn.prepareStatement("INSERT INTO users(email, password, name) VALUES (?, ?, ?)",
                    Statement.RETURN_GENERATED_KEYS);
            ps.setObject(1, email);
            ps.setObject(2, password);
            ps.setObject(3, name);
            return ps;
        }, holder)) {
            throw new RuntimeException("Insert User failed");
        }

        return new User(holder.getKey().longValue(), name, password, email);
    }

    public int deleteUser(long id) {
        int rc = jdbcTemplate.update("DELETE FROM users WHERE id = ?", id);
        if (rc != 1) {
            throw new RuntimeException("User not found by id: " + id);
        }
        return rc;
    }
}
